function h_out = guidraw(h_fig, h_axes, control_command);

% GUIDRAW - interactively create a drawing
%
%    H_LINE = GUIDRAW(H_FIG, H_AXES, SHAPE) allows the user to
%    create a line drawing on the axes H_AXES.  The shape of the
%    drawing is specified by SHAPE ('BOX', 'ELLIPSE', 'POLYGON'
%    or 'POLYLINE').  The handle of the line/rectangle object is
%    returned as H_LINE.
%
%    GUIDRAW(H_FIG, H_AXES, 'start') is the WindowButtonDownFcn callback
%    routine for GUIDRAW.  It serves to initiate the drawing process
%    when the user initially presses the left mouse button.
%
%    GUIDRAW(H_FIG, H_AXES, 'extend') is the WindowButtonMotionFcn
%    callback routine for GUIDRAW.  It serves to update segments as
%    the user moves the mouse after pressing the left mouse button.
%
%    GUIDRAW(H_FIG, H_AXES, 'release') is the WindowButtonUpFcn callback
%    routine for GUIDRAW.  If the user releases the left mouse button, it
%    serves to complete a BOX/ELLIPSE drawing, or add the first segment
%    of a POLYGON or POLYLINE drawing.
%
%    GUIDRAW(H_FIG, H_AXES, 'addpoint') is the WindowButtonDownFcn
%    callback routine for GUIDRAW.  It serves to add vertices to
%    POLYGON or POLYLINE drawings when the user clicks the left
%    mouse button.  Drawings are terminated when a double-click
%    is detected.

% NOTE:  drawing a BOX/ELLIPSE only requires code from the initial call
%        the remaining commands apply to POLYGON/POLYLINE shapes only

% By:   S.C. Molitor (smolitor@med.unc.edu)
% Date: May 19, 2000

% initialize output to prevent MATLAB errors

if (nargout > 0)
   h_out = [];
end

% check input parameters

if (nargin ~= 3)
   return
elseif (~istype(h_fig, 'figure'))
   return
elseif (~istype(h_axes, 'axes'))
   return
elseif (~ischar(control_command) | isempty(control_command))
   return
end

% obtain current coordinates
% obtain previous selection type

get_point = get(h_axes, 'CurrentPoint');
select_type = get(h_fig, 'SelectionType');
xc = get_point(1, 1);
yc = get_point(1, 2);

% process control command

switch (control_command)
   
case 'BOX'			% create square rectangle
   [x1, y1, x2, y2, select_flag] = guirbsel(h_fig, h_axes);
   if (select_flag)
      h_line = rectangle(...
         'Curvature', [0 0], ...
         'Position', [x1 y1 (x2 - x1) (y2 - y1)], ...
         'Parent', h_axes, ...
         'EraseMode', 'xor');
   end
   
case 'ELLIPSE'		% create elliptical rectangle
   [x1, y1, x2, y2, select_flag] = guirbsel(h_fig, h_axes);
   if (select_flag)
      h_line = rectangle(...
         'Curvature', [1 1], ...
         'Position', [x1 y1 (x2 - x1) (y2 - y1)], ...
         'Parent', h_axes, ...
         'EraseMode', 'xor');
   end
   
case {'POLYLINE', 'POLYGON'}		% create POLYLINE/POLYGON
   
   % change current axes, pointer & UserData values
   % save previous values
   
   current_axes = get(h_fig, 'CurrentAxes');
   set(h_fig, 'CurrentAxes', h_axes);
   pointer_type = get(h_fig, 'Pointer');
   set(h_fig, 'Pointer', 'crosshair');
   fig_user = get(h_fig, 'UserData');
   set(h_fig, 'UserData', '');
   axes_user = get(h_axes, 'UserData');
   set(h_axes, 'UserData', []);
   
   % set ButtonDown & ButtonUp callbacks
   % do not disable previous ButtonMotion callback (pixel display)
   
   button_down = get(h_fig, 'WindowButtonDownFcn');
   set(h_fig, 'WindowButtonDownFcn', 'guidraw(gcf, gca, ''start'')');
   button_motion = get(h_fig, 'WindowButtonMotionFcn');
   if (isempty(button_motion))
      set(h_fig, 'WindowButtonMotionFcn', 'guidraw(gcf, gca, ''extend'')');
   else
      set(h_fig, 'WindowButtonMotionFcn', [button_motion '; guidraw(gcf, gca, ''extend'')']);
   end
   button_up = get(h_fig, 'WindowButtonUpFcn');
   set(h_fig, 'WindowButtonUpFcn', 'guidraw(gcf, gca, ''release'')');
   h_child = [h_fig; h_axes; get(h_axes, 'Children')];
   child_down = get(h_child, 'ButtonDownFcn');
   set(h_child, 'ButtonDownFcn', '');
   
   % wait for figure Tag to be set to 'done'
   % obtain drawing handle from UserData
   % reset figure settings & callbacks
   
   waitfor(h_fig, 'UserData', 'done');
   h_line = get(h_axes, 'UserData');
   set(h_fig, 'CurrentAxes', current_axes);
   set(h_fig, 'Pointer', pointer_type);
   set(h_fig, 'UserData', fig_user);
   set(h_axes, 'UserData', axes_user);
   set(h_fig, 'WindowButtonDownFcn', button_down);
   set(h_fig, 'WindowButtonMotionFcn', button_motion);
   set(h_fig, 'WindowButtonUpFcn', button_up);
   for i = 1 : min(length(h_child), length(child_down))
      set(h_child(i), 'ButtonDownFcn', child_down{i});
   end
   
   % delete redundant points resulting from double-click
   % close polygon figure if specified
   
   if (istype(h_line, 'line'))
      x_data = get(h_line, 'XData');
      y_data = get(h_line, 'YData');
      coord_index = [0 find((diff(x_data) ~= 0) | (diff(y_data) ~= 0))] + 1;
      if (length(coord_index) > 1)
         x_data = x_data(coord_index);
         y_data = y_data(coord_index);
      end
      if (strcmp(control_command, 'POLYGON'))
         x_data(end + 1) = x_data(1);
         y_data(end + 1) = y_data(1);
      end
      set(h_line, 'XData', x_data, 'YData', y_data);
   end
   
case 'start'		% initialize the drawing
   
   % check that first click is within axes limits
   % create line drawing object & save handle
   % reset WindowButtonDownFcn
   % otherwise set UserData to empty & Tag to 'done'
   
   if (axesflag(h_axes, xc, yc) & ~strcmp(select_type, 'open'))
      h_line = line([xc xc], [yc yc], ...
         'Parent', h_axes, ...
         'EraseMode', 'xor');
      set(h_axes, 'UserData', h_line);
   else
      set(h_axes, 'UserData', []);
      set(h_fig, 'UserData', 'done');
   end
   
case 'extend'		% extend the drawing
   
   % check for valid line drawing
   % update last coordinate with current point
   
   h_line = get(h_axes, 'UserData');
   if (istype(h_line, 'line') & axesflag(h_axes, xc, yc))
      x_data = get(h_line, 'XData');
      y_data = get(h_line, 'YData');
      x_data(end) = xc;
      y_data(end) = yc;
      set(h_line, 'XData', x_data, 'YData', y_data);
   end
   
case 'release'		% complete first line segment
   
   % check for valid line drawing
   % set ButtonDownFcn for adding segments
   
   h_line = get(h_axes, 'UserData');
   if (istype(h_line, 'line'))
      x_data = get(h_line, 'XData');
      y_data = get(h_line, 'YData');
      if (all([diff(x_data) diff(y_data)] == 0))
         delete(h_line);
         h_line = [];
         set(h_fig, 'UserData', 'done');
      else
         guidraw(h_fig, h_axes, 'addpoint');
         set(h_fig, 'WindowButtonDownFcn', 'guidraw(gcf, gca, ''addpoint'')');
         set(h_fig, 'WindowButtonUpFcn', '');
      end
   else
      set(h_fig, 'UserData', 'done');
   end
   
case 'addpoint'	% add vertex
   
   % check for valid line drawing
   % if double click, end drawing
   % otherwise add next point
   
   h_line = get(h_axes, 'UserData');
   if (istype(h_line, 'line'))
      if (strcmp(select_type, 'open'))
         set(h_fig, 'UserData', 'done');
      elseif (axesflag(h_axes, xc, yc))
         x_data = get(h_line, 'XData');
         y_data = get(h_line, 'YData');
         x_data(end + 1) = xc;
         y_data(end + 1) = yc;
         set(h_line, 'XData', x_data, 'YData', y_data);
      end
   else
      set(h_fig, 'UserData', 'done');
   end
end

% assign output if specified

if (nargout > 0)
   h_out = h_line;
end
return
